Skip to content

Conversation

ickshonpe
Copy link
Contributor

@ickshonpe ickshonpe commented Jul 30, 2025

Objective

Add an input module to bevy_text with the components, systems and helper functions necessary for a user to implement a basic text input.

Just the changes to bevy_text split out from #20326.

Solution

Features:

  • Placeholder text for empty inputs
  • Password mode.
  • Filters applied at edit.
  • Autopropagated events emitted on submission, invalid edits and text changes.
  • Input method agnostic, users queue TextEdits to make changes to the text input's buffer.
  • Max character limit
  • Responsive height sizing.
  • Vertical and horizontal scrolling
  • Fixes the line cropping while vertical scrolling bug in cosmic-text.
  • Full undo and redo.
  • Text selection.
  • Cut, copy and paste.
  • Numeric input modes.
  • Single line modes.
  • Support for the common navigation actions like home, end, page down, page up, next word, end of paragraph, etc.
  • Backspace.
  • Overwrite mode.
  • Click to place cursor.
  • Drag to select.
  • Double click to select a word.
  • Triple click to set select a line.
  • Indent and unident.
  • A TextInputValue component that contains a copy of the buffer's text and is automatically synchronised on edits. On insertion the TextInputValues contents replace the current text in the TextInputBuffer.

Testing

Basic example using bevy_sprite for rendering:

cargo run --example text_input_2d.rs

@alice-i-cecile alice-i-cecile added this to the 0.17 milestone Jul 30, 2025
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-UI Graphical user interfaces, styles, layouts, and widgets A-Text Rendering and layout for characters S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 30, 2025
@ickshonpe ickshonpe added C-Feature A new feature, making something new possible A-Text Rendering and layout for characters S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed C-Feature A new feature, making something new possible A-Text Rendering and layout for characters S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 30, 2025
Copy link
Contributor

@viridia viridia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments, really just nits. Fantastic work, overall!

@@ -0,0 +1,1340 @@
use crate::buffer_dimensions;
use crate::load_font_to_fontdb;
use crate::CosmicFontSystem;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason why these don't use the more compact (multiple imports per line) format? I suppose single-line-per-import makes merging easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes just been making so many changes, probably consolidate them once it's ready to merge.

/// Any actions that modify a text input's text so that it fails
/// to pass the filter are not applied.
#[derive(Component)]
pub enum TextInputFilter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really good. I like all the options here.

For something like a MMORPG I would probably make a custom filter for character names: alphanumeric, can have internal spaces but can't begin or end with a space.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for something like name entry, it's more natural to allow arbitrary edits and then perform any validation and trim any trailing or leading spaces etc after submission.

Perhaps we add an option to only apply the filter on submit, then refuse to submit if the filter fails and emit an InvalidSubmission event variant. It might be better left for the user to handle though, I'm not sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for something like name entry, it's more natural to allow arbitrary edits and then perform any validation and trim any trailing or leading spaces etc after submission.

You're right, that's better.

Perhaps we add an option to only apply the filter on submit, then refuse to submit if the filter fails and emit an InvalidSubmission event variant. It might be better left for the user to handle though, I'm not sure.

I'm going to put on my lecturer's hat and talk briefly about form validation, apologies for my long-windedness.

In the world of React.js, the common practice (which is supported by libraries such as react-hook-form) is to have two validation modes. This validation is done at the form level, not at the level of individual fields. That is, specialized field types such as numeric inputs still only accept digits (this is built in to the browser), but for more complex formats the validation is done by the form handler.

Initially the form is set to "validate on submit" mode, meaning that validation is not done until the user attempts to submit the form. The reason is that we don't want to distract the user with error messages while they are typing. This is especially true for "required field" errors. If the validation succeeds and the form is submitted successfully, then the user never sees an error message.

If validation fails, then the form will display error messages below each field that failed validation. In addition, the form now changes to "validate on type" mode, meaning that validation is done continuously as the user is correcting their mistakes, giving them instant feedback. Once all of the errors have been corrected, they can attempt to submit again.

Libraries like react-hook-form allow custom validators to be defined for individual fields, where the validator doesn't just return a boolean but an error message or error code, allowing the message displayed to the user to include a description of what they did wrong. In Rust, this would probably mean returning a Result.

All this being said, I don't think we should include anything like this sort of functionality in our text input. First, because most of our users don't need to fill in complex forms, and displaying error messages below input fields is way out of scope here. If someone wants to build a third-party crate for form handling, it should be simple enough given the various events that you've defined.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically also you would just apply a debounce to validation so you get errors pre-submit but you don't spam your backend while you are typing. This is the pattern I've most commonly see.

editor.set_redraw(true);
}

/// Apply the queued actions for each text input, with special case for submit actions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a public function, I'd like a bit more explanation on when/where/how this would be used. Is this something meant to be called by app developers, or only from widget authors?

More generally: there are a lot of public functions in this module, and I'm unclear as to the scope of their intended use: are they meant to be called only by other bevy crates, or by game developers generally? I wish there was some way to indicate this in rustdoc.

Copy link
Contributor Author

@ickshonpe ickshonpe Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure what would end up in the text module and what would go in the widget implementation so I was keeping things pub mostly while I was moving them back and forth.

Most of the systems aren't intended to be used outside of the bevy-text crate but they might need to be public or at least part of a public system set so that the schedule can be set up correctly to work with different layout algorithms.

@viridia
Copy link
Contributor

viridia commented Jul 30, 2025

Release note suggestion:


A long-standing feature request from our users is support for text input. Whether the user is creating a new character, logging in with a username and password, or creating a new save file, it's vitally important for them to be able to enter a string of text. Unfortunately, writing a robust and feature-rich text input widget is not easy, especially one that supports all of the expected capabilities (such as undo, range selection, and scrolling). This effort is made much easier now that Bevy has incorporated the cosmic crate for text handling.

(add bullet list of features here)

What we are releasing in this milestone is only the lowest-level, foundational elements of text editing. These are not complete, self-contained widgets, which will come in the next milestone, but more like a toolkit with "some assembly required". For now, you can write your own text input widgets, following the provided examples as a guide.

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Aug 5, 2025
@alice-i-cecile
Copy link
Member

Can we split this apart to avoid blocking on the undo question?

@mogambro
Copy link
Contributor

Please, please, please split it!

From a user perspective it would be super dope if we had finally support for text input in bevy itself.

Yes, I know that it's not 100% after this PR, but perfect is the enemy of good and 80% is more than 0%!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Text Rendering and layout for characters A-UI Graphical user interfaces, styles, layouts, and widgets C-Bug An unexpected or incorrect behavior C-Feature A new feature, making something new possible D-Complex Quite challenging from either a design or technical perspective. Ask for help! M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide M-Needs-Release-Note Work that should be called out in the blog due to impact S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants